<?php

namespace Yolo\Service;

use Yolo\Errors\ExceptionRegistry;
use Yolo\Errors\Exceptions\DuplicateSymbolException;
use Yolo\Errors\Exceptions\ErrorTypeNotFoundException;
use Yolo\Errors\Exceptions\SymbolNotFoundException;
use Yolo\Errors\Exceptions\YoloException;
use Yolo\Errors\ResponseError;

class ApiGateway
{
    const OK_RESPONSE = [
        'message' => 'ok'
    ];

    public static function defaultResponseError(): array
    {
        return [
            'module' => 'system',
            'type' => 'system',
            'code' => 500,
            'message' => 'System error.',
            'symbol' => 'system',
            'metadata' => [],
            'extra' => [
                'http' => [
                    'status' => 500,
                ],
            ],
        ];
    }

    /**
     * 从metadata里获取商家ID
     * @param array $metadata
     * @return int|null
     */
    public static function getMerchantIdFromMetadata(array $metadata): ?int
    {
        return $metadata['merchant'] ?? null;
    }

    /**
     * 从metadata里获取账户ID
     * @param array $metadata
     * @return int|null
     */
    public static function getAccountIdFromMetadata(array $metadata): ?int
    {
        return $metadata['usr'] ?? null;
    }

    /**
     * 从metadata里获取客户端IP
     * @param array $metadata
     * @return string|null
     */
    public static function getClientIpFromMetadata(array $metadata): ?string
    {
        return $metadata['clientIp'] ?? null;
    }

    /**
     * 从metadata里获取请求头（只会返回请求中指定的请求头）
     * @param array $metadata
     * @return array
     */
    public static function getHeadersFromMetadata(array $metadata): array
    {
        return $metadata['headers'] ?? [];
    }

    /**
     * 注册一个错误响应
     * @param ResponseError $responseError
     * @return void
     * @throws DuplicateSymbolException|ErrorTypeNotFoundException
     */
    public static function registerResponseError(ResponseError $responseError): void
    {
        $registry = ExceptionRegistry::inst();
        $symbol = $responseError->getSymbol();
        $exception = $registry->get($symbol);
        if ($exception === null) {
            throw new DuplicateSymbolException([
                'symbol' => $symbol,
            ]);
        }

        $moduleTypes = $registry->getModuleTypes();

        if (!isset($moduleTypes[$responseError->getType()])) {
            throw new ErrorTypeNotFoundException([
                'type' => $responseError->getType(),
            ]);
        }

        $registry->register($responseError);
    }

    /**
     * @param string $symbol
     * @param array $metadata
     * @return YoloException
     */
    public static function responseError(string $symbol, array $metadata = []): YoloException
    {
        $error = ExceptionRegistry::inst()->get($symbol);
        if ($error === null) {
            return new SymbolNotFoundException([
                'symbol' => $symbol
            ]);
        }

        $ex = new YoloException(
            $error->getMessage(),
            $error->getCode()
        );
        $ex->setSystemException($error);
        if ($metadata) {
            $ex->setMetadata($metadata);
        }

        return $ex;
    }

    public static function responseNewError(ResponseError $error): YoloException
    {
        $ex = new YoloException(
            $error->getMessage(),
            $error->getCode()
        );
        $ex->setSystemException($error);
        return $ex;
    }

    /**
     * 列表响应
     * @param int $total 总数
     * @param array $items 列表
     * @return array
     */
    public static function responseList(int $total, array $items): array
    {
        return [
            'totalRows' => $total,
            'items' => $items,
        ];
    }
}
